package com.viknix.threadpool.manager.cluster.lookup;

import com.viknix.threadpool.manager.cluster.core.Member;
import com.viknix.threadpool.manager.cluster.file.FileChangeEvent;
import com.viknix.threadpool.manager.cluster.file.FileWatcher;
import com.viknix.threadpool.manager.cluster.file.WatchFileCenter;
import com.viknix.threadpool.manager.server.dependence.exception.ServerProcessException;
import com.viknix.threadpool.manager.server.dependence.util.EnvUtil;
import com.viknix.threadpool.manager.cluster.util.MemberUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Author: Dongqi
 * @Date: 2021/11/10 19:21
 * @Version 1.0
 * @Description: 文件寻址模式
 */
@Slf4j
public class FileConfigMemberLookup extends AbstractMemberLookup {

    /**
     * 文件变动检测者，当 C:\Users\15333\tpm\conf\cluster.conf 文件发生变动时，会调用 watcher
     */
    private FileWatcher watcher = new FileWatcher() {
        @Override
        public void onChange(FileChangeEvent event) {
            // 从磁盘上重新读取 cluster.conf 文件
            readClusterConfFromDisk();
        }

        @Override
        public boolean interest(String context) {
            return StringUtils.contains(context, "cluster.conf");
        }
    };

    /**
     * 初始化的时候调用
     *
     * @throws ServerProcessException
     */
    @Override
    public void start() throws ServerProcessException {
        if (start.compareAndSet(false, true)) {
            // 从磁盘上读取 cluster.conf
            readClusterConfFromDisk();

            // Use the inotify mechanism to monitor file changes and automatically
            // trigger the reading of cluster.conf
            try {
                // 使用 inotify 机制监视文件更改，触发重新读取 cluster.conf
                // 当 C:\Users\15333\tpm\conf\cluster.conf 文件发生变动时，会调用 watcher
                WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), watcher);
            } catch (Throwable e) {
                log.error(">>> 😒 An exception occurred in the launch file monitor : {}", e.getMessage());
            }
        }
    }

    /**
     * 从磁盘上重新读取 cluster.conf 文件
     */
    private void readClusterConfFromDisk() {

        Collection<Member> tmpMembers = new ArrayList<>();
        try {
            // 读取 cluster.conf 文件，返回集群列表 ip:port ip:port
            List<String> tmp = EnvUtil.readClusterConf();
            // 将每个集群节点封装成 Member 对象
            // 注意这里的集合中节点的状态并不是最终注册到 集群节点管理中心 ServerMemberManager 中的状态
            tmpMembers = MemberUtil.readServerConf(tmp);
        } catch (Throwable e) {
            log.error(">>> 😒 tpm-XXXX [serverlist] failed to get serverlist from disk!, error : {}", e.getMessage());
        }
        // 判断集群节点是否有变更，如果有变更更新内存中节点信息，同时持久化新节点信息持久化到cluster.conf
        // 发布 MembersChangeEvent 事件
        afterLookup(tmpMembers);
    }
}
